package controller

import (
	"fmt"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"soffice/config"
	"soffice/entity"
	"soffice/service"

	"github.com/gin-gonic/gin"
)

// @Summary 将文档转换为HTML
// @Description 上传Office文档并转换为HTML格式返回，支持图片自动处理和缓存优化
// @Tags 文件转换
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "要转换的文档文件（支持pdf, doc, docx, odt, odp, pptx, ppt, ods, xlsx, xls）"
// @Success 200 {object} entity.ConvertResponse "转换成功"
// @Failure 400 {object} entity.ConvertResponse "请求错误"
// @Failure 500 {object} entity.ConvertResponse "服务器错误"
// @Router /convert-to-html [post]
func ConvertToHTMLHandler(c *gin.Context) {
	var uploadedFilePath, outputHTMLPath string

	defer func() {
		// 清理上传的源文件
		if uploadedFilePath != "" {
			if err := os.Remove(uploadedFilePath); err != nil {
				log.Printf("删除源文件失败 %s: %v", uploadedFilePath, err)
			} else {
				// log.Printf("已删除源文件: %s", uploadedFilePath)
			}
		}

		// 清理临时图片文件
		if outputHTMLPath != "" {
			fileNameWithoutExt := strings.TrimSuffix(filepath.Base(outputHTMLPath), filepath.Ext(outputHTMLPath))
			service.CleanupTempFiles(filepath.Dir(outputHTMLPath), fileNameWithoutExt)
		}
	}()

	// 检查文件上传
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  "请上传文件",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 检查是否为PDF且设置了远程转换环境变量
	fileExt := strings.ToLower(filepath.Ext(file.Filename))
	if fileExt == ".pdf" && os.Getenv("REMOTE_PDF_API_URL") != "" {
		// 使用远程PDF转换
		files := []*multipart.FileHeader{file}
		success, htmlContent, _, _, _, errorMsg := service.RemoteConvertPDFToHTML(files)
		code := 200
		resultMsg := ""
		resultData := make(map[string]interface{})

		if success {
			resultData["htmlContent"] = htmlContent
		} else {
			code = 500
			resultMsg = errorMsg
		}

		response := entity.ConvertResponse{
			Code:       code,
			ResultMsg:  resultMsg,
			ResultData: resultData,
		}
		status := http.StatusOK
		if !success {
			status = http.StatusInternalServerError
		}
		c.JSON(status, response)
		return
	}

	// 检查文件大小
	if file.Size > service.MaxFileSize {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  "文件大小超过限制（200MB）",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 检查文件格式
	if !service.IsAllowedFormat(file.Filename) {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  fmt.Sprintf("不支持的文件格式。支持的格式: %s", strings.Join(service.GetAllowedFormats(), ", ")),
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 生成唯一文件名并保存
	fileExt = filepath.Ext(file.Filename)
	fileName := service.GenerateUniqueFileName(fileExt)
	uploadedFilePath = filepath.Join("static", "images", fileName)

	if err := service.SaveUploadedFile(file, uploadedFilePath); err != nil {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  "保存文件失败: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}

	log.Printf("开始转换文件: %s", file.Filename)

	// 直接处理 Markdown -> HTML
	if strings.EqualFold(fileExt, ".md") {
		htmlContent, htmlPath, err := service.ProcessMarkdownToHTML(uploadedFilePath, fileName, fileExt)
		if err != nil {
			c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
				Code:       500,
				ResultMsg:  err.Error(),
				ResultData: make(map[string]interface{}),
			})
			return
		}

		outputHTMLPath = htmlPath

		c.JSON(http.StatusOK, entity.ConvertResponse{
			Code:       200,
			ResultMsg:  "",
			ResultData: map[string]interface{}{"htmlContent": htmlContent},
		})
		return
	}

	// 转换文件为HTML
	outputDir := "out"
	if err := service.ConvertToHTML(uploadedFilePath, outputDir); err != nil {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 查找生成的HTML文件
	fileNameWithoutExt := strings.TrimSuffix(fileName, fileExt)
	outputHTMLPath = filepath.Join(outputDir, fileNameWithoutExt+".html")

	// 检查HTML文件是否生成
	if _, err := os.Stat(outputHTMLPath); os.IsNotExist(err) {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  "HTML文件生成失败",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 读取HTML内容
	htmlBytes, err := os.ReadFile(outputHTMLPath)
	if err != nil {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  "读取HTML文件失败: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}

	htmlContent := string(htmlBytes)

	// 删除头尾 div
	htmlContent = service.RemoveHeaderFooterDivs(htmlContent)

	log.Printf("文件转换成功: %s", file.Filename)
	log.Printf("HTML文件已保存到: %s", outputHTMLPath)

	// 处理HTML中的图片路径
	htmlFileName := fileNameWithoutExt + ".html"
	apiBasePath := config.GetAPIBasePath()
	apiBaseURL := "/" + apiBasePath

	// 对于 PDF 文件，先处理 base64 图片，再处理相对路径图片
	if fileExt == ".pdf" {
		htmlContent, err = service.ProcessBase64Images(htmlContent, htmlFileName, "static", apiBaseURL)
		if err != nil {
			log.Printf("处理 base64 图片时出错: %v", err)
		}
	}

	// 处理相对路径的图片
	htmlContent, err = service.ProcessHTMLImages(htmlContent, htmlFileName, outputDir, "static", apiBaseURL)
	if err != nil {
		log.Printf("处理HTML图片时出错: %v", err)
	}

	// 将处理后的HTML内容写回文件
	if err := os.WriteFile(outputHTMLPath, []byte(htmlContent), 0644); err != nil {
		log.Printf("写入HTML文件失败: %v", err)
	}

	// 返回响应
	response := entity.ConvertResponse{
		Code:       200,
		ResultMsg:  "",
		ResultData: map[string]interface{}{"htmlContent": htmlContent},
	}

	c.JSON(http.StatusOK, response)
}

// @Summary 上传文件并返回URL
// @Description 上传任意文件，返回可访问的URL地址，URL前缀由getBaseURL决定
// @Tags 文件上传
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "要上传的文件"
// @Success 200 {object} map[string]interface{} "上传成功"
// @Failure 400 {object} map[string]interface{} "请求错误"
// @Failure 500 {object} map[string]interface{} "服务器错误"
// @Router /upload-file [post]
func UploadFileHandler(c *gin.Context) {
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  "请上传文件",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 生成唯一文件名并保存
	fileExt := filepath.Ext(file.Filename)
	fileHash, err := service.ComputeFileHash(file)
	if err != nil {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  "计算文件哈希失败: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}
	if len(fileHash) > 16 {
		fileHash = fileHash[:16]
	}
	fileName := fileHash + fileExt
	uploadPath := filepath.Join("images", fileName)

	// 打开上传的文件
	src, err := file.Open()
	if err != nil {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  "打开文件失败: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}
	defer src.Close()

	// 保存到存储
	fileURL, err := service.SaveUploadedFileToStorage(src, uploadPath)
	if err != nil {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  "保存文件失败: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}

	c.JSON(http.StatusOK, entity.ConvertResponse{
		Code:       200,
		ResultMsg:  "",
		ResultData: map[string]interface{}{"url": fileURL},
	})
}

// @Summary 将HTML字符串转换为PDF、Word或Markdown
// @Description 接收HTML字符串，将其中的图片转换为base64后，使用soffice转换为PDF或Word文件，或转换为Markdown格式。支持的格式：pdf, word, docx, md
// @Tags 文件转换
// @Accept json
// @Produce json
// @Param request body entity.ConvertHTMLRequest true "转换请求"
// @Success 200 {object} entity.ConvertResponse "转换成功，返回文件下载URL"
// @Failure 400 {object} entity.ConvertResponse "请求错误"
// @Failure 500 {object} entity.ConvertResponse "服务器错误"
// @Router /convert-html-to-file [post]
func ConvertHTMLToFileHandler(c *gin.Context) {
	var req entity.ConvertHTMLRequest

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  "请求参数错误: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 验证格式
	format := strings.ToLower(req.Format)
	if format != "pdf" && format != "word" && format != "docx" && format != "md" {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  "不支持的格式，仅支持: pdf, word, docx, md",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	log.Printf("开始转换HTML到%s", format)

	// 转换HTML到文件
	outputFilePath, err := service.ConvertHTMLStringToFile(req.HTMLContent, format)
	if err != nil {
		c.JSON(http.StatusInternalServerError, entity.ConvertResponse{
			Code:       500,
			ResultMsg:  "转换失败: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 生成下载URL
	fileName := filepath.Base(outputFilePath)
	apiBasePath := config.GetAPIBasePath()
	fileURL := "/" + apiBasePath + "/download/" + fileName

	log.Printf("HTML转换成功，文件: %s", fileName)

	c.JSON(http.StatusOK, entity.ConvertResponse{
		Code:      200,
		ResultMsg: "",
		ResultData: map[string]interface{}{
			"fileUrl":  fileURL,
			"fileName": fileName,
		},
	})
}

// @Summary 下载转换后的文件
// @Description 下载之前转换生成的PDF或Word文件
// @Tags 文件下载
// @Produce application/octet-stream
// @Param filename path string true "文件名"
// @Success 200 {file} binary "文件内容"
// @Failure 404 {object} entity.ConvertResponse "文件不存在"
// @Router /download/{filename} [get]
func DownloadFileHandler(c *gin.Context) {
	filename := c.Param("filename")

	// 安全检查：防止路径遍历
	if strings.Contains(filename, "..") {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  "非法的文件名",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	filePath := filepath.Join("out", filename)

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, entity.ConvertResponse{
			Code:       404,
			ResultMsg:  "文件不存在",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 设置响应头
	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Content-Disposition", "attachment; filename="+filename)

	// 根据文件扩展名设置Content-Type
	ext := strings.ToLower(filepath.Ext(filename))
	switch ext {
	case ".pdf":
		c.Header("Content-Type", "application/pdf")
	case ".docx":
		c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
	case ".md":
		c.Header("Content-Type", "text/markdown; charset=utf-8")
	default:
		c.Header("Content-Type", "application/octet-stream")
	}

	c.File(filePath)
}

// @Summary 下载存储中的文件（支持MinIO和本地存储）
// @Description 通过当前服务转发下载存储中的文件，支持路径参数
// @Tags 文件下载
// @Produce application/octet-stream
// @Param filepath path string true "文件路径（支持子目录，如：images/xxx.png）"
// @Success 200 {file} binary "文件内容"
// @Failure 404 {object} entity.ConvertResponse "文件不存在"
// @Router /download-file/{filepath} [get]
func DownloadStorageFileHandler(c *gin.Context) {
	// 获取完整的文件路径（包括子目录）
	filepath := c.Param("filepath")

	// 安全检查：防止路径遍历
	if strings.Contains(filepath, "..") {
		c.JSON(http.StatusBadRequest, entity.ConvertResponse{
			Code:       400,
			ResultMsg:  "非法的文件路径",
			ResultData: make(map[string]interface{}),
		})
		return
	}

	// 从存储获取文件
	st := service.GetStorageInstance()
	fileReader, err := st.GetFile(filepath)
	if err != nil {
		c.JSON(http.StatusNotFound, entity.ConvertResponse{
			Code:       404,
			ResultMsg:  "文件不存在: " + err.Error(),
			ResultData: make(map[string]interface{}),
		})
		return
	}
	defer fileReader.Close()

	// 获取文件名（用于Content-Disposition）
	filename := filepath[strings.LastIndex(filepath, "/")+1:]

	// 设置响应头
	c.Header("Content-Description", "File Transfer")
	c.Header("Content-Transfer-Encoding", "binary")
	c.Header("Content-Disposition", "inline; filename="+filename)

	// 根据文件扩展名设置Content-Type
	ext := strings.ToLower(filepath[strings.LastIndex(filepath, "."):])
	switch ext {
	case ".jpg", ".jpeg":
		c.Header("Content-Type", "image/jpeg")
	case ".png":
		c.Header("Content-Type", "image/png")
	case ".gif":
		c.Header("Content-Type", "image/gif")
	case ".webp":
		c.Header("Content-Type", "image/webp")
	case ".svg":
		c.Header("Content-Type", "image/svg+xml")
	case ".pdf":
		c.Header("Content-Type", "application/pdf")
	case ".docx":
		c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
	case ".md":
		c.Header("Content-Type", "text/markdown; charset=utf-8")
	default:
		c.Header("Content-Type", "application/octet-stream")
	}

	// 流式传输文件内容
	c.DataFromReader(http.StatusOK, -1, c.GetHeader("Content-Type"), fileReader, nil)
}

// 注册所有API路由
func RegisterRoutes(r *gin.Engine, apiBasePath string) {
	// 添加 CORS 中间件，允许所有来源跨域访问
	importCors := false
	if !importCors {
		importCors = true
		// 仅在首次注册时导入
		// ...existing code...
	}
	r.Use(func(c *gin.Context) {
		origin := c.Request.Header.Get("Origin")
		if origin != "" {
			c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
		} else {
			c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		}
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization, Accept, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}
		c.Next()
	})
	api := r.Group("/" + apiBasePath)
	api.POST("/convert-to-html", ConvertToHTMLHandler)
	api.POST("/upload-file", UploadFileHandler)
	api.POST("/convert-html-to-file", ConvertHTMLToFileHandler)
	api.GET("/download/:filename", DownloadFileHandler)
	api.GET("/download-file/*filepath", DownloadStorageFileHandler)
}
